#include <stdio.h>
#include <math.h>

#include "na_1.2.h"

typedef double (*Functor)(const double);

inline double itrFunction1( const double x0 )
{
    return x0 * x0 + x0 - 3.0;
}

inline double itrFunction2( const double x0 )
{
    return 3.0 / ( x0 * x0 );
}

inline double itrFunction3( const double x0 )
{
    return x0 - ( x0 * x0 - 3.0 ) / 8;
}

inline double itrFunction4( const double x0 )
{
    return x0 - ( x0 * x0 - 3.0 ) / 4;
}

inline double itrFunction5( const double x0 )
{
    return x0 - ( x0 * x0 - 3.0 );
}

inline double itrFunction6( const double x0 )
{
    double dbx0 = 2.0 * x0;
    double t = x0 - ( x0 * x0 - 3.0) / dbx0;
    return t - ( t * t - 3.0 )/ dbx0;
}

inline bool isConverged( const double x0, const double x1)
{
	return fabs( x0 - x1 ) < LIMIT_EPSILON;
}

inline void logStep( unsigned int i, double x0, double x1 ) 
{
	printf("iteration step %2d, x%d \t= %1.12f, x%d \t= %1.12f \n", i+1, i, x0, i+1, x1);
}


int na_12()
{
    printf("Start the NA experiment 1.2, basic iteration (2)\n");

    unsigned int    type = 0;
    double          x0 = 2.0; //the given init value
    double          x1 = 0.0;
    Functor         itrFunc[6]; 

    itrFunc[0] = &itrFunction1;
    itrFunc[1] = &itrFunction2;
    itrFunc[2] = &itrFunction3;
    itrFunc[3] = &itrFunction4;
    itrFunc[4] = &itrFunction5;
    itrFunc[5] = &itrFunction6;

    for( unsigned int input = 0; (type < 1) || (type > 6); )
    {
        printf("Please input the iteration type ( 1 ~ 6 ):");
        scanf_s("%d", &type);
    }
    
    printf("Start iteration with equation %d \n", type--);

    unsigned int i = 0;
    for ( ; !isConverged( x0, x1 ); ++i )
    {
        x0 = x1;
        x1 = itrFunc[type]( x0 );
        logStep( i, x0, x1 );
    }

 	if ( !isConverged(x0, x1) )
	{
		printf("Stopped for divergening...\n");
	}
	else
	{
        printf("Converged with %d steps, reaches at x = %1.12f \n", i, x1);
    }
	   
    printf("End of iteration\n");

	return 0;
}
